﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_DEFINES_H
#define _UXS_DEFINES_H

#pragma once

#include "../Platforms/Platforms.h"

#ifndef UX_EXPORT
# ifdef __UX_BUILD_STATIC_LIB__
#	define UX_EXPORT
# else
#	ifdef __UX_BUILD__
#		define UX_EXPORT					UX_DLL_EXPORT
#	else
#		define UX_EXPORT					UX_DLL_IMPORT
#	endif
# endif	// __UX_BUILD_STATIC_LIB__
#endif	// UX_EXPORT


#ifndef CALLBACK
#	ifdef PLATFORM_WINDOWS
#		define CALLBACK						__stdcall
#	else
#		define CALLBACK
#	endif
#endif


#if not defined(ARGS)
#	define ARGS(_arg)						_args
#endif

#if not defined(__UX_EMPTY_ARGS)
#	define __UX_EMPTY_ARGS(_args)			
#endif


#ifdef __UX_DEBUG__
#	define DEBUG_ONLY						ARGS
#	define RELEASE_ONLY						__UX_EMPTY_ARGS
#else
#	define DEBUG_ONLY						__UX_EMPTY_ARGS
#	define RELEASE_ONLY						ARGS
#endif	// __UX_DEBUG__


#ifdef PLATFORM_TYPE_MOBILE
#	define MOBILE_ONLY						ARGS
#	define DESCTOP_ONLY						__UX_EMPTY_ARGS
#else
#	define MOBILE_ONLY						__UX_EMPTY_ARGS
#	define DESCTOP_ONLY						ARGS
#endif	// PLATFORM_TYPE_MOBILE


// Asserts //
#ifdef __UX_DEBUG__
# ifndef ASSERT_EXT
#	define ASSERT_EXT( _b_val, _p_msg )		assert2(_b_val, _p_msg)
# endif
# define ASSUME( _b_val )					ASSERT( _b_val )
#else
# define ASSUME( _b_val )					UX_ASSUME( _b_val )
# ifndef ASSERT_EXT
#	define ASSERT_EXT( _b_val, _p_msg )		void()
# endif
#endif	// __UX_DEBUG__

#define ASSERT( _b_val )					ASSERT_EXT( (_b_val), #_b_val )



// Static Assert //
#define	STATIC_ASSERT( _b_val, _text )		static_assert( _b_val, _text )


#define TODO( _text )						ASSERT_EXT( false, _text )
#define WARNING( _text )					ASSERT_EXT( false, _text )
#define STATIC_WARNING( _text )				STATIC_ASSERT( false, _text )
#define STATIC_ASSERTE( ... )				STATIC_ASSERT( (__VA_ARGS__), #__VA_ARGS__ )

#define CONSOLE_OUTPUT( ... )				_hidden_::printf( __VA_ARGS__ )


// temporary code //
#if defined(UX_TEMP_CODE)
#	define TEMP_CODE_MARKER()				{} // nothing
#	define TEMP_CODE						ARGS
#else
#	define TEMP_CODE_MARKER()				STATIC_WARNING( "temporary code!!!" )
#	define TEMP_CODE						__UX_EMPTY_ARGS
#endif


// try / catch //
#if defined( UX_CATCHING_EXCEPTIONS_DISABLE ) or defined( PLATFORM_ANDROID )
#	define TRY								
#	define THROW( _val_ )
#	define CATCH( _val_, ... )
#else
#	define TRY								try
#	define THROW( _val_ )					throw( _val_ )
#	define CATCH( _val_, ... )				catch( _val_ ) __VA_ARGS__
#endif	// UX_CATCHING_EXCEPTIONS_DISABLE


// inline //
#define INLINE	UX_FORCE_INLINE


// Other //

// compile-time count of array
#define COUNT_OF( _arr )					(sizeof(_arr) / sizeof(_arr[0]))

// convert to string
#define TO_ANSI_STRING(...)					(#__VA_ARGS__)
#define TO_WIDE_STRING(...)					(L#__VA_ARGS__)

#ifdef UX_UNICODE
#	define UX_IS_UNICODE					1
#	define TOSTRING							TO_WIDE_STRING
#else
#	define UX_IS_UNICODE					0
#	define TOSTRING							TO_ANSI_STRING
#endif



// helpers for function parameters (GLSL style)
#define IN			/* input argument (can skip) */
#define OUT			/* output argument */
#define INOUT		/* input and output argument (not recomended) */



// for each
#define FOR( _counter, _container ) \
	for (usize _counter = 0; _counter < (_container).Count(); ++_counter)

#define FORv( _counter, _value, _container ) \
	for (usize _counter = (_value); _counter < (_container).Count(); ++_counter)

#define FORc( _counter, _container ) \
	for (; _counter < (_container).Count(); ++_counter)

#define FOR_rev( _counter, _container ) \
	for (usize _counter = (_container).Count()-1; _counter < (_container).Count(); --_counter)

#define FORv_rev( _counter, _value, _container ) \
	for (usize _counter = (_value); _counter < (_container).Count(); --_counter)

#define FORc_rev( _counter, _container ) \
	for (; _counter < (_container).Count(); --_counter)



// range for
#define FOR_range( _counter, _begin, _end ) \
	for (usize _counter = _begin; _counter < _end; ++_counter)

#define FOR_range_rev( _counter, _begin, _end ) \
	for (usize _counter = _end-1; (_counter >= _begin and _counter < _end); --_counter)

#define FOR_range_t( _type, _counter, _begin, _end ) \
	for (_type _counter = _begin; _counter < _end; ++_counter) 



// iterator for each
#ifdef UX_AUTO_SUPPERTED

#	define iFOR( _iter, _container ) \
		for (auto _iter = (_container).Begin(); not (_container).IsEnd( _iter ); ++_iter )

#	define iFORv( _iter, _value, _container ) \
		for (auto _iter = _value; not (_container).IsEnd( _iter ); ++_iter )

#	define iFOR_rev( _iter, _container ) \
		for (auto _iter = (_container).End(); not (_container).IsBegin( _iter ); --_iter )

#else

#	define iFOR( _iter, _container )
		STATIC_WARNING( "iFOR not supported in this compiler" );

#	define iFORv( _iter, _value, _container )
		STATIC_WARNING( "iFORv not supported in this compiler" );

#	define iFOR_rev( _iter, _container )
		STATIC_WARNING( "iFOR_rev not supported in this compiler" );

#endif



// swap
#define UX_SWAP_NEW( _type, _tmp, _a, _b ) \
	_type  _tmp = _a;  _a = _b;  _b = _tmp;

#define UX_SWAP( _tmp, _a, _b ) \
	_tmp = _a;  _a = _b;  _b = _tmp;


// bit operations
#define UX_ENUM_BIT_OPERATIONS( _type ) \
	typedef NearInt::Unsigned<_type>::type		__uint_bit_t; \
	\
	template <typename T>	inline _type & operator |=  (_type& left, const T& right)			{ return left = _type( __uint_bit_t(left) |  __uint_bit_t(right) ); } \
	template <typename T>	inline _type & operator &=  (_type& left, const T& right)			{ return left = _type( __uint_bit_t(left) &  __uint_bit_t(right) ); } \
	template <typename T>	inline _type & operator ^=  (_type& left, const T& right)			{ return left = _type( __uint_bit_t(left) ^  __uint_bit_t(right) ); } \
	template <typename T>	inline _type & operator >>= (_type& left, const T& right)			{ return left = _type( __uint_bit_t(left) >> __uint_bit_t(right) ); } \
	template <typename T>	inline _type & operator <<= (_type& left, const T& right)			{ return left = _type( __uint_bit_t(left) << __uint_bit_t(right) ); } \
	\
							inline _type   operator |   (const _type& left, const _type& right)	{ return _type( __uint_bit_t(left) |  __uint_bit_t(right) ); } \
							inline _type   operator &   (const _type& left, const _type& right)	{ return _type( __uint_bit_t(left) &  __uint_bit_t(right) ); } \
							inline _type   operator ^   (const _type& left, const _type& right)	{ return _type( __uint_bit_t(left) ^  __uint_bit_t(right) ); } \
							inline _type   operator >>  (const _type& left, const _type& right)	{ return _type( __uint_bit_t(left) >> __uint_bit_t(right) ); } \
							inline _type   operator <<  (const _type& left, const _type& right)	{ return _type( __uint_bit_t(left) << __uint_bit_t(right) ); } \
	\
	template <typename T>	inline _type   operator |   (const _type& left, const T& right)		{ return _type( __uint_bit_t(left) |  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator &   (const _type& left, const T& right)		{ return _type( __uint_bit_t(left) &  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator ^   (const _type& left, const T& right)		{ return _type( __uint_bit_t(left) ^  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator >>  (const _type& left, const T& right)		{ return _type( __uint_bit_t(left) >> __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator <<  (const _type& left, const T& right)		{ return _type( __uint_bit_t(left) << __uint_bit_t(right) ); } \
	\
	template <typename T>	inline _type   operator |   (const T& left, const _type& right)		{ return _type( __uint_bit_t(left) |  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator &   (const T& left, const _type& right)		{ return _type( __uint_bit_t(left) &  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator ^   (const T& left, const _type& right)		{ return _type( __uint_bit_t(left) ^  __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator >>  (const T& left, const _type& right)		{ return _type( __uint_bit_t(left) >> __uint_bit_t(right) ); } \
	template <typename T>	inline _type   operator <<  (const T& left, const _type& right)		{ return _type( __uint_bit_t(left) << __uint_bit_t(right) ); } \
	\
							inline _type   operator ~   (const _type& value)					{ return _type(~__uint_bit_t(value)); } \
							inline bool    operator !   (const _type& value)					{ return not __uint_bit_t(value); } \


// add operations
#define UX_ENUM_ADD_OPERATIONS( _type ) \
	typedef NearInt::Unsigned<_type>::type		__uint_math_t; \
	typedef NearInt::Signed<_type>::type		__int_math_t; \
	\
							inline _type & operator ++ (_type& value)							{ return value = _type( __uint_math_t(value)+1 ); } \
							inline _type & operator -- (_type& value)							{ return value = _type( __uint_math_t(value)-1 ); }	 \
	\
							inline _type   operator ++ (_type& value, int)						{ _type t(value);  ++value;  return t; } \
							inline _type   operator -- (_type& value, int)						{ _type t(value);  --value;  return t; } \
	\
	template <typename T>	inline _type & operator += (_type& left, const T& right)			{ return left = _type( __uint_math_t(left) + __uint_math_t(right) ); } \
	template <typename T>	inline _type & operator -= (_type& left, const T& right)			{ return left = _type( __uint_math_t(left) - __uint_math_t(right) ); } \
	\
							inline _type   operator +  (const _type& left, const _type& right)	{ return _type( __uint_math_t(left) + __uint_math_t(right) ); } \
							inline _type   operator -  (const _type& left, const _type& right)	{ return _type( __uint_math_t(left) - __uint_math_t(right) ); } \
	\
	template <typename T>	inline _type   operator +  (const _type& left, const T& right)		{ return _type( __uint_math_t(left) + __uint_math_t(right) ); } \
	template <typename T>	inline _type   operator -  (const _type& left, const T& right)		{ return _type( __uint_math_t(left) - __uint_math_t(right) ); } \
	\
	template <typename T>	inline _type   operator +  (const T& left, const _type& right)		{ return _type( __uint_math_t(left) + __uint_math_t(right) ); } \
	template <typename T>	inline _type   operator -  (const T& left, const _type& right)		{ return _type( __uint_math_t(left) - __uint_math_t(right) ); } \
	\
							inline _type   operator +  (const _type& value)						{ return _type( +__uint_math_t(value) ); } \
							inline _type   operator -  (const _type& value)						{ return _type( -__int_math_t(value) ); } \


// all operations
#define UX_ENUM_OPERATIONS( _type ) \
	UX_ENUM_BIT_OPERATIONS( _type ) \
	UX_ENUM_ADD_OPERATIONS( _type )


// Prototipes for MetaData
#define UX_DECLARE_META_OBJECT( _type )
#define UX_CREATE_META_OBJECT( _type, _meta_class )
#define UX_ENUM_META_OBJECT( _type )
#define UX_DECLARE_META_TYPEDEF( _type, _base_type ) 


//-------------------------------------------------------------------

#endif	// _UXS_DEFINES_H